home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d13 / book.exe / LANRES.C < prev    next >
C/C++ Source or Header  |  1991-09-22  |  17KB  |  664 lines

  1. /*
  2. // LANRES.C        Memory resident functions for LAN information utility
  3. //
  4. // (c) Copyright 1990, 1991 Adrian King.
  5. //
  6. //
  7. //        This code was developed for inclusion in the book
  8. //        "Running LANtastic", by Adrian King, published by
  9. //        Bantam Books, October 1991.
  10. //
  11. //    This product uses the TesSeRact(tm) Ram-Resident Library and
  12. //    supports the TesSeRact Standard for Ram-Resident Program Comm-
  13. //    unication. For information about TesSeRact, contact the TesSeRact
  14. //    Development Team at:
  15. //
  16. //        TesSeRact Development Team
  17. //        1657 The Fairways
  18. //        Suite 101
  19. //        Jenkintown PA 19046
  20. //        1-215-884-3373
  21. //
  22. //        Compuserve:    70731,20
  23. //        MCIMAIL:    315-5415
  24. //
  25. // This is the main module for the memory resident piece. It turns
  26. // itself into a memory resident program and then waits for network
  27. // messages. Some messages elicit a response, others cause a message
  28. // to be popped up on the screen.
  29. //
  30. // Run the program with the three optional switches: BOOT, POP or BEEP.
  31. // For example:
  32. //
  33. //        lanres /boot=n /pop=n /beep=y
  34. //
  35. // Will disable remote booting, turn off message popup and leave message
  36. // arrival beeping on. The default is: /boot=y /pop=y /beep=y.
  37. //
  38. // This program can be removed from memory by typing Alt+L.
  39. //
  40. // Make sure to compile this program with a -DBACKGROUND switch.
  41. //
  42. // $Header:   C:/USR/LANBOOK/SRC2/LAN/VCS/LANRES.C_V   1.2   22 Sep 1991  9:16:52  $
  43. //
  44. // $Log:   C:/USR/LANBOOK/SRC2/LAN/VCS/LANRES.C_V  $
  45. //
  46. //   Rev 1.2   22 Sep 1991  9:16:52
  47. //Added correct TesSeRact copyright notice.
  48. //Cleaned up some comments.
  49. //
  50. //   Rev 1.1   29 Aug 1991 12:37:30
  51. //Modified delay in replying to status messages to avoid message
  52. //collisions at receiver. Delay is calculated as a random number
  53. //(derived from the node name.) This seems to remove most of the
  54. //collisions.
  55. //
  56. //   Rev 1.0   13 Jul 1991 11:19:54
  57. //Initial revision.
  58. //
  59. */
  60.   
  61.     //    Standard includes
  62.  
  63. #include "string.h"
  64. #include "dos.h"
  65.  
  66.     //    Local includes    
  67.  
  68. #include "nos.h"
  69. #include "noslib.h"
  70. #include "lan.h"
  71.  
  72.     //    Includes needed for the interface to TesSeRact
  73.  
  74. #include "tess.h"
  75.  
  76.     //    Declarations to interface with assembler module (NOSIF.ASM)
  77.  
  78. extern void far nowhere();        // Null routine in NOSIF.ASM
  79.  
  80. FARPROC oldservice = nowhere;    // Holds address of previous message service
  81.                                 // handler. Calls null routine until set up.
  82.  
  83. FARPROC    olddos = nowhere;        // Holds address of previous DOS service
  84.                                 // vector. Null call until set up.
  85.  
  86. extern void far msg_interrupt();// Routines in NOSIF.ASM called by NOS
  87. FARPROC msg_service = msg_interrupt;    
  88.  
  89. extern void far nos_interrupt();
  90. FARPROC dos_service = nos_interrupt;
  91.  
  92. extern void far msg_proc();
  93. FARPROC fpmsg_proc = msg_proc;
  94.  
  95. extern void far dowork();
  96. FARPROC fpdowork = dowork;
  97.  
  98. extern WORD bworktodo;            // Incremented when dowork() must be called
  99.                                 // Decremented after work is done
  100.  
  101.     //    Global declarations for this module
  102.  
  103. #ifdef __TURBOC__
  104. unsigned _heaplen = 1024;        // Limit heap to 1K
  105. unsigned _stklen = 2048;        // Limit stack length to 2K
  106. #endif
  107.  
  108. struct workq workq[D_WORKITEMS];// Queue of work to be done
  109.  
  110. BOOL bBootflag = TRUE;            // Allow remote reboot, FALSE disallows
  111. BOOL bPopflag = FALSE;            // Disallow message popup, TRUE allows
  112. BOOL bBeepflag = FALSE;            // Message arrival beep, FALSE disallows  
  113. BOOL bQuietflag = FALSE;        // Quiet at shut down, FALSE means quiet
  114. char cpMachine[D_NAMESZ];        // Name of this node 
  115. char cpOther[D_NAMESZ];            // Name of other machine
  116. int  nMsgflag;                    // Old message flag
  117. unsigned nReplydelay = 0;        // Pseudo random # for replay delay
  118.  
  119. struct msgstats msgstats = { 0, 0, 0, 0, 0};
  120.  
  121.     // Forward declarations
  122.  
  123. void parsecmd();                // Analyze command arguments
  124. void help();                    // Print help and quit
  125. void far msg_proc();            // Routine called to process messages
  126. extern void far reboot();        // Reboot function
  127.  
  128.     //
  129.     //    TSRMAIN
  130.     //
  131.     //    This routine is called when the popup key combination is hit.
  132.     //    (Alt+L). It prints some stats, resets all the NOS vectors and 
  133.     //    unloads the program.
  134.     //
  135.     
  136. void far pascal TsrMain()
  137. {
  138.     int i;
  139.  
  140.     if (bQuietflag){
  141.         NOSprintstr("\n\nLANRES status on ");
  142.         NOSprintstr(lannode[0].cpName);
  143.         NOSprintstr("\n\n");
  144.         NOSprintstr("\nReceived 0x");
  145.         NOSprintx(msgstats.in);
  146.         NOSprintstr(" messages.\nSent 0x");
  147.         NOSprintx(msgstats.out);
  148.         NOSprintstr(" messages.\nMessage service busy 0x");
  149.         NOSprintx(msgstats.msgbusy);
  150.         NOSprintstr(" times.\nReceived 0x");
  151.         NOSprintx(msgstats.statusack);
  152.         NOSprintstr(" status ack messages.\nReceived 0x");
  153.         NOSprintx(msgstats.unknown);
  154.         NOSprintstr(" unidentifiable messages.\n\n");
  155.         NOSprintstr("Machines active on the network:\n");
  156.         for (i = 0; i < D_NODES; i++){
  157.             if (lannode[i].cpName[0] != '\0'){
  158.                 NOSprintstr(lannode[i].cpName);
  159.                 NOSprintstr(", flags = 0x");
  160.                 NOSprintx(lannode[i].wFlags);
  161.                 NOSprintstr("\n");
  162.             }
  163.         }
  164.         NOSprintstr("Unloading...\n");
  165.     }
  166.  
  167.     (void)NOSSetMsgFlag(nMsgflag);        // Reset message flag and service
  168.     (void)NOSSetMsgVector(oldservice);    // vectors.
  169.     (void)NOSSetDOSVector(olddos);
  170.  
  171.     TsRelease(TSRid);                    // Release this TSR from memory
  172. }
  173.  
  174.     //
  175.     //    TSRUSERPROC
  176.     //
  177.     //    Called (via TesSeRact) from the foreground program.
  178.     //    The call is either to clear the node table (prior to
  179.     //    asking the network nodes for an update), or a request
  180.     //    for the updated table. In the first case the parameter is 0.
  181.     //    Otherwise the parameter is the address of entry 1 in the network
  182.     //  node table. Entries 1 through D_NODES-1 from the background
  183.     //    table are copied to    this address.
  184.     //
  185.  
  186. void far pascal TsrUserProc(fpN)
  187. void far *fpN;
  188. {
  189.     char far *fp = (char far *)fpN;
  190.     char *cpN = (char *)&lannode[1];
  191.     int i;
  192.  
  193.     if (fpN == (void far *)0){
  194.         for (i = 1; i < D_NODES; i++)
  195.             lannode[i].cpName[0] = '\0';
  196.     } else {
  197.         for (i = (D_NODES - 1) * sizeof (struct lannode); i > 0; i--)
  198.             *fp++ = *cpN++;
  199.     }
  200. }
  201.  
  202.     //
  203.     //    MAIN
  204.     //
  205.  
  206. void main(argc, argv)
  207. int argc;
  208. char *argv[];
  209. {
  210.     int i;
  211.     BOOL bSet;
  212.     int n;
  213.     char *cp;
  214.  
  215.     NOSprintstr("LANRES version 1.0 - (C) Copyright 1991 Adrian King\n");
  216.  
  217.                 // Check to see if we are already loaded, and
  218.                 // abort if so
  219.  
  220.     if (TsCheckResident((char far *)TSRIdStr, (unsigned far *)&TSRid) 
  221.             == 0xFFFF){
  222.                 // Already loaded
  223.         TsRestore2f();
  224.         FATAL(E_LANLIBL);
  225.     }
  226.         
  227.                 // Parse command arguments
  228.  
  229.     if (argc != 1)
  230.         for (i = 1; i < argc; i++)
  231.             parsecmd(argv[i]);
  232.                 
  233.     if ((i = NOSPresence())== -1)    // Test for some part of NOS loaded
  234.         FATAL(E_NONOS);
  235.  
  236.     initnodetable();                // Set up network node table
  237.  
  238.                                     // Get name of this node
  239.     if (NOSGetMachineName(cpMachine, &n, &bSet) == -1)
  240.         FATAL(E_GETNAME);
  241.     if (!bSet)
  242.         FATAL(E_NONAME);
  243.  
  244.     cp = strchr(cpMachine, ' ');
  245.     if (cp != (char *)0)
  246.         *cp = '\0';                    // Null terminate the name
  247.                                        // Make it entry 0 in the table
  248.     addname(cpMachine, i);
  249.  
  250.                                     // Calculate the status message reply
  251.                                     // delay based on this node's network
  252.                                     // name. See dowork() for more info.
  253.     for (n = 0; n < strlen(cpMachine); n++)
  254.         nReplydelay += cpMachine[n];
  255.     nReplydelay *= 3;
  256.  
  257.     initwork();                        // Set up work queue
  258.  
  259.                                       // Get and save message service vector
  260.     if (NOSGetMsgVector(&oldservice) == -1)
  261.         FATAL(E_GETMSGVEC);
  262.  
  263.     NOSGetMsgFlag(&nMsgflag);        // Save message service flag
  264.  
  265.         //
  266.         // Set message processing flag so that delivery to message 
  267.         // service occurs. If beeping was off, keep it off. Otherwise
  268.         // set it to what the bBeepflag says. NOTE: By default, beeping
  269.         // is OFF. 
  270.         // 
  271.         // If popup was off, keep it off. Otherwise set it to what 
  272.         // bPopflag says.
  273.         //
  274.  
  275.     i = MPB_deliver;
  276.     if (bBeepflag)
  277.         i |= (nMsgflag & MPB_beep);
  278.     if (bPopflag)
  279.         i |= (nMsgflag & MPB_auto_pop_up);
  280.  
  281.     if (NOSSetMsgFlag(i) == -1)
  282.         FATAL(E_SETMSGFLAG);
  283.                                     // Save and set DOS service vector
  284.     if (NOSGetDOSVector(&olddos) == -1)
  285.         FATAL(E_GETDOSVEC);
  286.  
  287.     if (NOSSetDOSVector(dos_service) == -1)
  288.         FATAL(E_SETDOSVEC);
  289.                                     // Set address of our message service
  290.     if (NOSSetMsgVector(msg_service) == -1)
  291.         FATAL(E_SETMSGVEC);
  292.  
  293.                 //
  294.                 // Go resident. Alt+L will unload the program.
  295.                 //
  296.     i = SizeOfCode();
  297.     if (TsDoInit(TSRHOT_L, 
  298.                     TSRPOPALT, 
  299.                         TSRUSEPOPUP+TSRUSEUSER+NOPOPGRAPH,
  300.                             i)
  301.         ){
  302.                 // Error trying to go resident
  303.         FATAL(E_GORES);
  304.     }
  305. }
  306.  
  307.     //
  308.     //    INITWORK
  309.     //
  310.     //    Initialize work queue. Called once from main().
  311.     //
  312.  
  313. void initwork()
  314. {
  315.     int i;
  316.  
  317.     for (i = 0; i < D_WORKITEMS; i++)
  318.         freework(&workq[i]);
  319. }
  320.  
  321.     //
  322.     //    FREEWORK
  323.     //
  324.     //    Free an entry in the work queue
  325.     //
  326.  
  327. void freework(cpW)
  328. struct workq *cpW;
  329. {
  330.     entercrit();
  331.     cpW->wType = 0;
  332.     leavecrit();
  333. }
  334.  
  335.     //
  336.     //    NEXTWORK
  337.     //
  338.     //    Get next work item in the work queue. Returns 0 if there
  339.     //    is nothing there.
  340.     //
  341.  
  342. struct workq *nextwork()
  343. {
  344.     int i;
  345.     
  346.     entercrit();
  347.  
  348.     for (i = 0; i < D_WORKITEMS; i++){
  349.         if (workq[i].wType != 0){
  350.             leavecrit();
  351.             return(&workq[i]);
  352.         }
  353.     }
  354.  
  355.     leavecrit();
  356.     return (struct workq *)0;
  357. }
  358.  
  359.     //
  360.     //    ALLOCWORK
  361.     //
  362.     //    Allocate an empty work queue item. Returns 0 if none are
  363.     //    available.
  364.     //
  365.  
  366. struct workq *allocwork()
  367. {
  368.     int i;
  369.     
  370.     entercrit();
  371.  
  372.     for (i = 0; i < D_WORKITEMS; i++){
  373.         if (workq[i].wType == 0){
  374.             workq[i].wType = -1;
  375.             leavecrit();
  376.             return (&workq[i]);
  377.         }
  378.     }
  379.  
  380.     leavecrit();
  381.     return (struct workq *)0;
  382. }
  383.  
  384.     //
  385.     //    MSG_PROC
  386.     //
  387.     //    Private message processing service
  388.     //
  389.     //    This routine is called from the assembler msg_interrupt 
  390.     //    (in NOSIF.ASM). It either acts on the message or queues
  391.     //    up a work item to be processed by dowork() later.
  392.     //
  393.     //    If the work queue is full, then the message will be lost.
  394.     //
  395.  
  396. void far msg_proc(fpMsg)
  397. struct message_buffer far *fpMsg;
  398. {
  399.     struct workq *cpWork;                // Points to workq item in use
  400.     int n;
  401.     char cpN[D_NAMESZ];
  402.     int nMsgtype;
  403.  
  404.     msgstats.in++;                        // Update count of msgs received
  405.                                         // Copy in sender's name
  406.     copyfartonear(fpMsg->MB_originator, cpN, D_NAMESZ);
  407.  
  408.     nMsgtype = fpMsg->MB_type;
  409.  
  410.     switch (nMsgtype){
  411.  
  412.         case MBT_LANstatusack:            // Response to status enquiry
  413.             msgstats.statusack++;
  414.                                         // Build flags word
  415.             n = D_lanbios;
  416.             n |= (fpMsg->MB_text[1] == 'R')?D_redir:0;
  417.             n |= (fpMsg->MB_text[2] == 'S')?D_server:0;
  418.             n |= (fpMsg->MB_text[3] == 'L')?D_lanpup:0;
  419.     
  420.                                         // Add name of responder to table
  421.             if (addname(cpN, n) != 0)
  422.                 NOSprintstr("msg_proc(): error adding node name\n");
  423.             return;
  424.                 
  425.         case MBT_LANstatus:                // Request for status
  426.         case MBT_LANsend:                // Broadcast message
  427.                                         // Ignore if from self
  428.             if (nodenamecmp(lannode[0].cpName, cpN)==0)
  429.                 return;
  430.  
  431.         case MBT_LANtext:                // Plain text message
  432.         case MBT_LANbootack:            // Acknowledgement of boot request
  433.         case MBT_LANbootden:            // Denial of boot request
  434.         case MBT_LANwarmboot:            // Warm boot this machine
  435.         case MBT_LANcoldboot:            // Cold boot this machine
  436.  
  437.         default:                        // Collects normal NOS messages
  438.                 //
  439.                 // Allocate a workq entry. If none are available then lose
  440.                 // the message.
  441.                 //
  442.  
  443.             cpWork = allocwork();
  444.  
  445.             if (cpWork == (struct workq *)0){
  446.                 msgstats.msgbusy++;
  447.                 return;
  448.             }
  449.  
  450.                                         // Copy in the msg and its type
  451.             copyfartonear((char far *)fpMsg, (char *)&cpWork->M, 
  452.                             sizeof(struct message_buffer));
  453.             cpWork->wType = nMsgtype;
  454.  
  455.             bworktodo++;                // Show there is work to be done
  456.             return;
  457.     };
  458. }        
  459.  
  460.     //
  461.     //    DOWORK
  462.     //
  463.     //    Called from NOSIF.ASM when LANtastic calls the DOS service vector
  464.     //    and the bworktodo flag is set to show that there is some work to
  465.     //    be done. 
  466.     //
  467.     //    When this routine is called then it is safe to call DOS itself.
  468.     //  However, NOTHING is set up that enables you to do so. The PSP is
  469.     //  wrong, the stack is not yours, etc etc. Calling NOS routines is
  470.     //  okay because the NOS sets itself up properly. Unless you do extra
  471.     //  work, you cannot make INT 21H calls (for example.)
  472.     //
  473.  
  474. void far dowork()
  475. {
  476.     int n;
  477.     char *cp1, *cp2;
  478.     struct workq *cpWork;                // Points to work queue entry
  479.  
  480.     while (bworktodo){
  481.         cpWork = nextwork();            // Pick up work queue entry pointer
  482.                                         // Return if null - "shouldn't happen"
  483.         if (cpWork == (struct workq *)0){
  484.             return;
  485.         }
  486.  
  487.         switch (cpWork->wType){
  488.  
  489.             case MBT_LANstatus:            // Request for status, respond with
  490.                                            // what is loaded on this node plus
  491.                                            // its name.
  492.                 gennrsl();
  493.  
  494.                 cp1 = cpWork->M.MB_text;// Address of message data area
  495.                 for (n = 0; n < 4; n++)
  496.                     *cp1++ = cpNRSL[n];
  497.  
  498.                 cp2 = " active on ";
  499.                 while ((*cp1 = *cp2) != '\0'){
  500.                     cp1++;
  501.                     cp2++;
  502.                 }
  503.  
  504.                 for (n = 0; n < D_NAMESZ; n++)
  505.                     *cp1++ = lannode[0].cpName[n]; 
  506.  
  507.                     //
  508.                     // NOS only buffers one message. A network status 
  509.                     // enquiry may cause many replies. Some will get lost
  510.                     // due to collisions at the receiver. So, we delay the
  511.                     // response according to the pseudo random number
  512.                     // calculated as a function of the machine's 
  513.                     // name. This helps overcome message collisions at
  514.                     // the receiver. Obviously this is not reliable.
  515.                     //
  516.                 delay(nReplydelay);
  517.                 
  518.                 if (sendmessage(&(cpWork->M), cpWork->M.MB_originator, 
  519.                                     MBT_LANstatusack, (char *)0, -1) == -1)
  520.                     NOSprintstr("dowork() error responding to MBT_LANstatus\n");
  521.                 break;
  522.  
  523.             case MBT_LANwarmboot:        // Boot this machine
  524.             case MBT_LANcoldboot:
  525.                                         // Send acknowledgement or denial
  526.                 if (bBootflag)
  527.                     cp1 = "Reboot request acknowledged";
  528.                 else
  529.                     cp1 = "Reboot request rejected";
  530.  
  531.                                         // Don't acknowledge if the request
  532.                                         // came from this machine
  533.                 if (nodenamecmp(lannode[0].cpName, 
  534.                         &(cpWork->M.MB_originator))!=0)
  535.                     if (sendmessage(&(cpWork->M), cpWork->M.MB_originator, 
  536.                                     MBT_LANbootack, cp1, strlen(cp1)) == -1)
  537.                         NOSprintstr("dowork() error responding to boot\n");
  538.  
  539.                 if (bBootflag){
  540.                                         // Put up a message
  541.                                         // BUG: Might be wrong message
  542.                     NOSPopUpMsg(D_DISPTICKS, D_DISPLINE);
  543.                                         // Reboot
  544.                     if (cpWork->wType == MBT_LANwarmboot)
  545.                         reboot(WARMBOOT);            
  546.                     else
  547.                         reboot(COLDBOOT);
  548.                 }
  549.  
  550.                 break;
  551.  
  552.             case MBT_LANstatusack:
  553.             case MBT_LANtext:            // Display text message
  554.             case MBT_LANsend:            // Broadcast message
  555.             case MBT_LANbootack:
  556.             case MBT_general:
  557.                                         // Display the last message.
  558.                                         // BUG: may not be the last one held
  559.                                         // by NOS
  560.                 NOSPopUpMsg(D_DISPTICKS, D_DISPLINE);
  561.                 break;
  562.  
  563.             default:
  564.                 msgstats.unknown++;        // Got a bad message type
  565.                 break;
  566.         }
  567.  
  568.         freework(cpWork);                // Release work queue item
  569.  
  570.         entercrit();                    // Protect flag update
  571.         if (bworktodo)
  572.             bworktodo--;                // Decrement work flag
  573.         leavecrit();    
  574.     }
  575. }
  576.     
  577.     //
  578.     //    PARSECMD
  579.     //
  580.     //    Parse command arguments and set flags accordingly
  581.     //    Exit with a help message if argument is unknown.
  582.     //
  583.     //    Valid switches are:
  584.     //
  585.     //        /BOOT=
  586.     //        /POP=
  587.     //        /BEEP=
  588.     //
  589.     //    Followed by 'Yes' or 'No' (only 'y', 'Y', 'n' or 'N' are checked)
  590.     //
  591.  
  592. void parsecmd(s)
  593. char *s;
  594. {
  595.     struct cmdswitch {
  596.         char *cpId;            // Command switch id
  597.         BOOL *pbFlag;        // Pointer to related flag
  598.     };
  599.  
  600.     #define Nswitches 4
  601.  
  602.     struct cmdswitch cmdswitch[] = {"/BOOT=", &bBootflag, 
  603.                                     "/BEEP=", &bBeepflag,
  604.                                     "/POP=" , &bPopflag,
  605.                                     "/VERBOSE=", &bQuietflag
  606.                                      };
  607.     int i, j;
  608.  
  609.                               // Search switch table for match
  610.     for (i = 0; i < Nswitches; i++){
  611.                             // Length of string to match
  612.         j = strlen(cmdswitch[i].cpId);
  613.         if (strnicmp(s, cmdswitch[i].cpId, j) == 0){
  614.             if (s[j] == 'y' || s[j] == 'Y'){
  615.                 *cmdswitch[i].pbFlag = TRUE;
  616.                 return;
  617.             }
  618.             if (s[j] == 'n' || s[j] == 'N'){
  619.                 *cmdswitch[i].pbFlag = FALSE;
  620.                 return;
  621.             }
  622.         }
  623.     }
  624.  
  625.         // Couldn't identify this switch, or syntax incorrect
  626.  
  627.     help();
  628. }
  629.  
  630.     //    
  631.     //    HELP
  632.     //
  633.     //    Print a help message and exit
  634.     //
  635.  
  636. void help()
  637. {
  638.     NOSprintstr("\n\
  639. Available command switches for LANRES are:\n\n\
  640.     /BOOT=[Yes|No]    Allow or disallow remote booting\n\
  641.     /POP=[Yes|No]     Allow or disallow message popup\n\
  642.     /BEEP=[Yes|No]    Allow or disallow message arrival beeping\n\
  643.     /VERBOSE=[Yes|No] Show status messages when exiting\n\
  644. ");
  645.  
  646.     //    Exit - okay to call since we are not yet resident
  647. #ifdef __TURBOC__
  648.     _exit(0);
  649. #endif
  650. #ifndef __TURBOC__
  651.     exit(0);
  652. #endif
  653. }
  654.  
  655.     
  656.     
  657.  
  658.     
  659.  
  660.     
  661.     
  662.     
  663.     
  664.